package com.xhlj.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xhlj.controller.request_body.LoginBody;
import com.xhlj.entity.UserInfo;
import com.xhlj.security.DbUserDetailsManager;
import com.xhlj.security.captcha.CaptchaLoginAuthenticationToken;
import com.xhlj.service.UserInfoService;
import com.xhlj.utils.*;
import jakarta.annotation.Resource;
import jdk.jfr.Registered;
import org.apache.http.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class LoginService {
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    PasswordEncoder passwordEncoder;
    @Resource
    private JwtHelper jwtHelper;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    DbUserDetailsManager dbUserDetailsManager;
    static final String AppCode = "844f220c1e5c4659a7490c843dd18a9e";

    //TODO:采用手机号+密码的形式登录？是否采用？
    public Result login(String phoneNumber, String password) {
        try {
            // 创建 UsernamePasswordAuthenticationToken 实例
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phoneNumber, password);
            // 进行身份验证
            Authentication authentication = authenticationManager.authenticate(authenticationToken);
            authentication.getName();
            // 将认证信息设置到安全上下文中
            SecurityContext context = SecurityContextHolder.getContext();
            context.setAuthentication(authentication);
            if (authentication != null && authentication.isAuthenticated()) {
//               查询一下id
                LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(UserInfo::getUserPhone, phoneNumber);
                UserInfo user = userInfoService.getOne(wrapper);
                PayLoad payload = new PayLoad(user.getUserPhone(), UserType.fromValue(user.getUserType()), user.getUserId());
                String token = jwtHelper.createToken(payload);
                Map res = new HashMap();
                res.put("phoneNumber", phoneNumber);
                res.put("token", token);
                return Result.build(res, 200, "login success");
            }
            return Result.build(null, 200, "login failed");
        } catch (AuthenticationException e) {
            // 处理认证异常
            return Result.build(e.getMessage(), 500, "fail");
        }
    }

    //TODO:根据验证码登录，在此之前要调用接口先发送验证码
    public Result loginBySms(String phoneNumber, String captcha) {
//      生成Authentication,交给provider验证
        CaptchaLoginAuthenticationToken captchaLoginAuthenticationToken = new CaptchaLoginAuthenticationToken(phoneNumber, captcha, null);
        Authentication authentication = authenticationManager.authenticate(captchaLoginAuthenticationToken);
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authentication);
        if (authentication != null && authentication.isAuthenticated()) {
            //设置Security上下文
            //TODO:检查手机号格式
            if(RegexUtils.isPhoneInvalid(phoneNumber)){
                return Result.build(null, 400, "手机号格式错误");
            }

            //TODO:2.从redis中获取验证码，比较两个验证码，在authenticate中实现该流程
//            String code=stringRedisTemplate.opsForValue().get(RedisKey.Login_captcha_prefix + phoneNumber);
//            String codeInput=captcha;

            //若redis中没有验证码，验证码未发送或已经过期
//            if(code==null){
//                return Result.build(null,200,"请先发送验证码");
//            }
//            //两个验证码不同，提示验证码错误
//            if(!code.equals(codeInput)){
//                return Result.build(null,200,"验证码错误!");
//            }

            //TODO:验证码相同，查询用户是否存在，不存在就自动注册
            LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserInfo::getUserPhone, phoneNumber);
            UserInfo user = userInfoService.getOne(wrapper);

            //TODO:自动注册
            if(user==null){user=createUserWithPhone(phoneNumber);}


            PayLoad payload = new PayLoad(user.getUserPhone(), UserType.fromValue(user.getUserType()), user.getUserId());
            String token = jwtHelper.createToken(payload);
            Map res = new HashMap();
            res.put("phoneNumber", phoneNumber);
            res.put("token", token);
            return Result.build(res, 200, "login by captcha success");
        }
        return Result.build(null, 400, "登录失败");
    }


    //TODO:发送验证码
    public Result<Map> sendCaptcha(String phoneNumber) {
        if(RegexUtils.isPhoneInvalid(phoneNumber)){
            return Result.build(null, 400, "手机号格式错误");
        }
        //TODO:生成六位随机验证码，并存入redis
        String key = RedisKey.Login_captcha_prefix + phoneNumber;
        ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
        //直接调用hutool工具包依赖中的工具类实现
        String code = RandomUtil.randomNumbers(6);
        sendCodeByAPI(phoneNumber, code);
        stringStringValueOperations.set(key, code, 300, TimeUnit.SECONDS);

        return Result.build(null, 200, "获取验证码成功");
    }

    //TODO:根据手机号创建新用户，用户名随机生成
    private UserInfo createUserWithPhone(String phone) {
        UserInfo user=new UserInfo();
        user.setUserPhone(phone);
        user.setUserNickName(SystemConstants.USER_NICK_NAME_PREFIX + RandomUtil.randomString(6));
        //默认为线上观众
        user.setUserType(1);

        userInfoService.save(user);
        return user;
    }

    //TODO:验证码发送的外接口调用--国阳云平台
    public String sendCodeByAPI(String phone, String code) {
        String host = "https://gyytz.market.alicloudapi.com";
        String path = "/sms/smsSend";
        String method = "POST";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + AppCode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("mobile", phone);
        querys.put("param", "**code**:" + code + ",**minute**:5");
//smsSignId（短信前缀）和templateId（短信模板），可登录国阳云控制台自助申请。参考文档：http://help.guoyangyun.com/Problem/Qm.html
        querys.put("smsSignId", "2e65b1bb3d054466b82f0c9d125465e2");
        querys.put("templateId", "908e94ccf08b4476ba6c876d13f084ad");
        Map<String, String> bodys = new HashMap<String, String>();
        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println(response.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //TODO:注册
    public Result register(LoginBody loginBody) {
        String captcha = stringRedisTemplate.opsForValue().get(RedisKey.Login_captcha_prefix + loginBody.getPhoneNumber());
        if (!RegexUtils.isPhoneInvalid(loginBody.getPhoneNumber()) && !StringUtils.isEmpty(loginBody.getPassword())
                && (captcha.equals(loginBody.getCaptcha())) && loginBody.getUserType() != null
        ) {
            User user = new User(loginBody.getPhoneNumber(), loginBody.getPassword(), new ArrayList<>());
            dbUserDetailsManager.createUser(user);
            return Result.build(null, 200, "注册成功");
        }
        return Result.build(null, 400, "注册失败");
    }

    /*把redis里的token清除*/
    public Result logout(String token) {
        PayLoad payLoad = jwtHelper.getPayLoad(token);
        jwtHelper.removeToken(payLoad);
        return Result.build(null, 200, "退出登录成功");
    }
}
